/*
 *  Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 *  This file is part of e3net.
 *
 *  e3net is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  e3net is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with e3net. If not, see <https://www.gnu.org/licenses/>.
 */

package e3net

import (
	"errors"

	"gitee.com/ameise84/e3lock"
	"gitee.com/ameise84/e3net/internal/common"
)

func newStdTcpServer() *stdTcpServer {
	s := &stdTcpServer{
		acceptorMap: map[Tag]*stdTcpAcceptor{},
	}
	return s
}

type stdTcpServer struct {
	common.Service
	mu          e3lock.SpinLock
	acceptorMap map[Tag]*stdTcpAcceptor
}

func (ts *stdTcpServer) Start() error {
	if len(ts.acceptorMap) == 0 {
		return SocketErrorNoListener
	}
	return ts.Service.Start(func() (err error) {
		ts.mu.Lock()
		defer ts.mu.Unlock()
		for _, ln := range ts.acceptorMap {
			err = ln.start()
			if err != nil {
				break
			}
		}
		if err != nil {
			for _, l := range ts.acceptorMap {
				l.stop()
			}
		}
		return
	})
}

func (ts *stdTcpServer) Stop() {
	ts.Service.Stop(func() {
		ts.mu.Lock()
		defer ts.mu.Unlock()
		for _, ln := range ts.acceptorMap {
			delete(ts.acceptorMap, ln.tag)
			ln.stop()
			destroyStdTcpAcceptor(ln)
		}
	})
}

func (ts *stdTcpServer) AddAcceptor(hand AcceptHandler, tag Tag, addr string, pause bool, opts ...*TcpAcceptorOptions) (string, error) {
	if len(opts) == 0 {
		opts = append(opts, DefaultTcpAcceptorOptions())
	}

	ts.mu.Lock()
	defer ts.mu.Unlock()
	if _, ok := ts.acceptorMap[tag]; ok {
		return "", errors.New("the tag is added")
	}

	acceptor, err := createStdTcpAcceptor(tag, addr, opts[0], hand)

	if err != nil {
		return "", err
	}

	ts.acceptorMap[tag] = acceptor

	if pause {
		acceptor.pauseAccept()
	}
	if ts.IsRunning() {
		err = acceptor.start()
		if err != nil {
			destroyStdTcpAcceptor(acceptor)
			return "", err
		}
	}
	return acceptor.addr, nil
}

func (ts *stdTcpServer) RemoveAcceptor(tag Tag) {
	ts.mu.Lock()
	acceptor, ok := ts.acceptorMap[tag]
	delete(ts.acceptorMap, tag)
	ts.mu.Unlock()
	if ok {
		acceptor.stop()
		destroyStdTcpAcceptor(acceptor)
	}
}

func (ts *stdTcpServer) DisConnectByTag(tag Tag, pause bool) {
	ts.mu.Lock()
	acceptor, ok := ts.acceptorMap[tag]
	ts.mu.Unlock()

	if ok {
		isPause := acceptor.isPause()
		if !isPause {
			acceptor.pauseAccept()
		}
		acceptor.closeAllConn()
		if !isPause && !pause {
			acceptor.resumeAccept()
		}
	}
}

func (ts *stdTcpServer) DisConnectAll(pause bool) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	for _, acceptor := range ts.acceptorMap {
		isPause := acceptor.isPause()
		if !isPause {
			acceptor.pauseAccept()
		}
		acceptor.closeAllConn()
		if !isPause && !pause {
			acceptor.resumeAccept()
		}
	}
}

func (ts *stdTcpServer) PauseAcceptByTag(tag Tag) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	if acceptor, ok := ts.acceptorMap[tag]; ok {
		acceptor.pauseAccept()
	}
}

func (ts *stdTcpServer) PauseAccept() {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	for _, acceptor := range ts.acceptorMap {
		acceptor.pauseAccept()
	}
}

func (ts *stdTcpServer) ResumeAcceptByTag(tag Tag) {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	if acceptor, ok := ts.acceptorMap[tag]; ok {
		acceptor.resumeAccept()
	}
}

func (ts *stdTcpServer) ResumeAccept() {
	ts.mu.Lock()
	defer ts.mu.Unlock()
	for _, acceptor := range ts.acceptorMap {
		acceptor.resumeAccept()
	}
}
